package helper

import (
	"adam2/internal/constants"
	"adam2/internal/domain"
	"adam2/internal/model"
	"anubis-framework/pkg/io"
	"anubis-framework/pkg/util"
	"encoding/json"
	"gorm.io/gorm"
	"strings"
)

// DaoHelper dao层的通用方法
type DaoHelper struct {
	db *gorm.DB
}

func getDaoHelper() *DaoHelper {
	return &DaoHelper{domain.DataSource_.GormDb}
}

// 通常在某只股票除权之后，股票价格会大幅度下降，此时很多指标不再准确。由于数据库只有不复权的数据，因此在遇到一段时间内出现除权现象的股票时应当放弃。
// 这个函数的作用是判断某一段时间内，某只股票是否出现了除权的情况。
// 2020年8月24日之前，所有股票以下跌幅度超过11%为标准；2020年8月24日之后，创业板以22%为标准，其他板块的股票仍然是11%。
// 如果出现除权，则返回true；否则返回false
func FilterStockXr_stock(code string, beginDate string, endDate string) (bool, error) {
	// 某一只股票在某一段时间内升序排列
	var stockTransactionDataAllArray model.StockTransactionDataAllArray
	getDaoHelper().db.Raw("select * from stock_transaction_data_all t "+
		"where t.date_ between to_date(?, 'yyyy-mm-dd') and to_date(?, 'yyyy-mm-dd') "+
		"and t.code_ = ? "+
		"order by t.date_ asc", beginDate, endDate, code).Scan(&stockTransactionDataAllArray)
	if len(stockTransactionDataAllArray) != 0 {
		// 前一天股票的收盘价
		var lastClosePrice float64
		// 表示某一段时间内某只股票最大的下跌幅度
		var downPercentage float64
		for _, stockTransactionDataAll := range stockTransactionDataAllArray {
			// 如果是第一天，则跳过
			if lastClosePrice == 0 {
				lastClosePrice = stockTransactionDataAll.ClosePrice
				continue
			}

			// 表示某一段时间内某只股票最大的下跌幅度
			downPercentage = (stockTransactionDataAll.ClosePrice - lastClosePrice) / lastClosePrice * 100

			// 在2020-08-24之前，并且当下跌幅度大于-11%，就表示有可能是除权
			if util.Before(endDate, constants.JUDGEMENT_DATE) && downPercentage < -11 {
				return true, nil
			}

			// 在2020-08-24之后，如果股票代码以300开头，并且下跌幅度大于22%，则表示有可能是除权
			if util.AfterOrEqual(endDate, constants.JUDGEMENT_DATE) && strings.Compare(string(code[3]), "300") == 0 && downPercentage < -22 {
				return true, nil
			}

			// 在2020-08-24之后，如果股票代码不是300开头，并且下跌幅度大于11%，则表示有可能是除权
			if util.AfterOrEqual(endDate, constants.JUDGEMENT_DATE) && strings.Compare(string(code[3]), "300") != 0 && downPercentage < -11 {
				return true, nil
			}

			lastClosePrice = stockTransactionDataAll.ClosePrice
		}
	}
	return false, nil
}

// 通常在某只ETF除权之后，ETF价格会大幅度下降，此时很多指标不再准确。由于数据库只有不复权的数据，因此在遇到一段时间内出现除权现象的ETF时应当放弃。
// 这个函数的作用是判断某一段时间内，某只ETF是否出现了除权的情况。
// 如果某只ETF下跌超过了11%，表示出现除权，则返回true；否则返回false
func FilterStockXr_etf(code string, beginDate string, endDate string) (bool, error) {
	// 某一只ETF在某一段时间内升序排列
	var stockTransactionDataAllArray model.StockTransactionDataAllArray
	getDaoHelper().db.Raw("select * from etf_transaction_data t "+
		"where t.date_ between to_date(?, 'yyyy-mm-dd') and to_date(?, 'yyyy-mm-dd') "+
		"and t.code_ = ? "+
		"order by t.date_ asc", beginDate, endDate, code).Scan(&stockTransactionDataAllArray)
	if len(stockTransactionDataAllArray) != 0 {
		// 前一天ETF的收盘价
		var lastClosePrice float64
		// 表示某一段时间内某只ETF最大的下跌幅度
		var downPercentage float64
		for _, stockTransactionDataAll := range stockTransactionDataAllArray {
			// 如果是第一天，则跳过
			if lastClosePrice == 0 {
				lastClosePrice = stockTransactionDataAll.ClosePrice
				continue
			}

			// 表示某一段时间内某只ETF最大的下跌幅度
			downPercentage = (stockTransactionDataAll.ClosePrice - lastClosePrice) / lastClosePrice * 100

			// 如果下跌幅度大于-11%，就表示有可能是除权
			if downPercentage < -11 {
				return true, nil
			}

			lastClosePrice = stockTransactionDataAll.ClosePrice
		}
	}
	return false, nil
}

// 以json格式，返回买卖建议
func PrintBuySellSuggestionByJson_bias(printDate string) (string, error) {
	io.Infoln("以json方式，打印买卖建议，日期为[%s]", printDate)

	// 做多
	// 查找卖出建议和买入建议
	var robot7StockTransactRecordArray_bullSellSuggestion model.Robot7StockTransactRecordArray
	getDaoHelper().db.Raw("select * from robot7_stock_transact_record t "+
		"where t.sell_date=to_date(?,'yyyy-mm-dd') and t.sell_date is not null and t.sell_price is not null "+
		"and t.sell_amount is not null and t.direction=1", printDate).Scan(&robot7StockTransactRecordArray_bullSellSuggestion)
	var robot7StockTransactRecordArray_bullBuySuggestion model.Robot7StockTransactRecordArray
	getDaoHelper().db.Raw("select * from robot7_stock_transact_record t "+
		"where t.buy_date=to_date(?,'yyyy-mm-dd') and t.sell_date is null and t.sell_price is null and t.sell_amount is null "+
		"and t.direction=1", printDate).Scan(&robot7StockTransactRecordArray_bullBuySuggestion)

	var robotBuySellSuggestionByJson_bias domain.RobotBuySellSuggestionByJson_bias = domain.RobotBuySellSuggestionByJson_bias{}
	robotBuySellSuggestionByJson_bias.BullBuySuggestionArray = robot7StockTransactRecordArray_bullBuySuggestion
	robotBuySellSuggestionByJson_bias.BullSellSuggestionArray = robot7StockTransactRecordArray_bullSellSuggestion
	data, _ := json.MarshalIndent(&robotBuySellSuggestionByJson_bias, "", "\t")
	return string(data), nil
}

// 根据code，在StockTransactionDataAllArray中查找记录
func FindStockTransactionDataAllByCode(stockTransactionDataAllArry model.StockTransactionDataAllArray, code string) *model.StockTransactionDataAll {
	if stockTransactionDataAllArry != nil {
		for _, stockTransactionDataAll := range stockTransactionDataAllArry {
			if stockTransactionDataAll.Code == code {
				return stockTransactionDataAll
			}
		}
	}
	return nil
}
